﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;

using MongoDB.Driver;
using MongoDB.Driver.Linq;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Driver.Builders;
using MongoDB.Driver.GridFS;

using System.Threading;
using System.Threading.Tasks;

namespace SFR
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            //this.treeView1.DrawMode = System.Windows.Forms.TreeViewDrawMode.OwnerDrawAll;

            //this.treeView1.DrawNode += new DrawTreeNodeEventHandler(treeView_DrawNode);

            listBox1.SelectedIndexChanged += new EventHandler(listBox1_SelectedIndexChanged);
            
            _dbName = "docs";

            try
            {
                cli = new MongoClient();

                ms = cli.GetServer();

                md = ms.GetDatabase(_dbName);

                gfs = new MongoGridFS(md);

                openFileDialog1 = new OpenFileDialog();//import

                folderBrowserDialog1 = new FolderBrowserDialog();

                ListDb();

                TagsPerDocument = new Dictionary<string, bool>();

                toolStripStatusLabel1.Text = "Ready!";
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show("Error: "+ex.Message);
            }
        }

        void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            Doc p = (Doc)listBox1.SelectedItem;

            textBox7.Text = p.Comment;
            textBox6.Text = p.SubjectName;
        }


        //void treeView1_DrawNode(object sender, DrawTreeNodeEventArgs e)
        //{
        //    if (e.Node.GetNodeCount(true) == 0)
        //    //if (NodeWithCheckBox(e.Node))
        //    {
        //        // draw entry with checkbox
        //        e.Node.
        //    }
        //    else
        //    {
        //        e.DrawDefault = true;
        //    }
        //}

        string _dbName;
        MongoClient cli;
        MongoServer ms;
        MongoDatabase md;
        MongoGridFS gfs;

        OpenFileDialog openFileDialog1; //import
        FolderBrowserDialog folderBrowserDialog1; //export

        Dictionary<string, bool> TagsPerDocument;

        //Import
        private void button1_Click(object sender, EventArgs e)
        {
            FileInfo f;
            try
            {
                f = new FileInfo(textBox1.Text);
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show("Error: invalid file!"); return;
            }

            if (!f.Exists) { System.Windows.Forms.MessageBox.Show("Error: The file you have selected does not exist!"); return; }

            button1.Enabled = false;
            toolStripStatusLabel1.Text = "Importing: " + f.Name + " ...";

            if (!md.CollectionExists(_dbName))
            {
                md.CreateCollection(_dbName);
            }

            MongoCollection<Doc> _documents = md.GetCollection<Doc>(_dbName);
            //_documents.RemoveAll();
            
            //add file to GridFS
            Task<MongoGridFSFileInfo> taskA = Task.Factory.StartNew<MongoGridFSFileInfo>(() => { MongoGridFSFileInfo gfsi_thread = gfs.Upload(textBox1.Text); return gfsi_thread; });
            //taskA.Wait();

            //MongoGridFSFileInfo gfsi = gfs.Upload(textBox1.Text);
            taskA.ContinueWith((Task<MongoGridFSFileInfo> thistask) =>
            {
                MongoGridFSFileInfo gfsi = thistask.Result; 

                WriteConcernResult wc = _documents.Insert(new Doc()
                {
                    GridFsId = gfsi.Id.AsObjectId,
                    DocName = f.Name,
                    Tags = GetSelectedTags(treeView1),//new string[] {"Tag1","Tag2","Tag3"},
                    Comment = textBox4.Text,
                    SubjectName = textBox5.Text
                }
                );

                ListDb();

                //On import successful:
                button1.Enabled = true;
                toolStripStatusLabel1.Text = "File: \"" + f.Name + "\" imported successfully!";
                System.Windows.Forms.MessageBox.Show("Imported successfully");

            });
        }

        //export
        private void button2_Click(object sender, EventArgs e)
        {
            if (listBox1.SelectedIndex == -1)
            {
                System.Windows.Forms.MessageBox.Show("Error: No file for export selected!"); return;
            }
            if (!Directory.Exists(textBox2.Text))
            {
                System.Windows.Forms.MessageBox.Show("Error: Export directory does not exists!"); return;
            }

            try
            {
                MongoCollection<Doc> _documents = md.GetCollection<Doc>(_dbName);

                foreach (Doc item in _documents.FindAll())
                {
                    if (((Doc)listBox1.SelectedItem).DocName == item.DocName)
                    {
                        ObjectId _documentid = new ObjectId(item.GridFsId.ToString());

                        MongoGridFSFileInfo _fileInfo = md.GridFS.FindOne(Query.EQ("_id", _documentid));

                        string fullPath;
                        if (!textBox2.Text.EndsWith(Path.DirectorySeparatorChar.ToString()))
                            fullPath = textBox2.Text + Path.DirectorySeparatorChar + item.DocName;
                        else
                            fullPath = textBox2.Text + item.DocName;

                        toolStripStatusLabel1.Text = "Exporting: \"" + item.DocName+"\" ...";
                        FileStream fs = new FileStream(fullPath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
                        gfs.Download(fs, _fileInfo);
                        fs.Close();
                        toolStripStatusLabel1.Text = "File: \"" + item.DocName+"\" exported successfully!";
                        System.Windows.Forms.MessageBox.Show("Exported successfully");
                        //gfs.Download(textBox2.Text, _fileInfo);

                        //Console.WriteLine("Downloaded {0}", item.DocName);

                        //Console.WriteLine("DocName {0} dowloaded", item.DocName);
                    }

                }
            }
            catch (Exception ex)
            {
                System.Windows.Forms.MessageBox.Show("Error: " + ex.Message);
                return;
            }
        }

        private void button4_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                //System.IO.StreamReader sr = new
                //   System.IO.StreamReader(openFileDialog1.FileName);

                //MessageBox.Show(sr.ReadToEnd());
                //sr.Close();
                this.textBox1.Text = openFileDialog1.FileName;
            }
        }

        private void ListDb()
        {
            //listBox1.Items.Clear();
            ////list db
            //MongoCollection<Doc> _documents = md.GetCollection<Doc>(_dbName);

            //foreach (Doc item in _documents.FindAll())
            //{
            //    //ObjectId _documentid = new ObjectId(item.DocId.ToString());

            //    //Console.WriteLine("Downloaded {0}", item.DocName);

            //    listBox1.Items.Add(item);
            //}
            buttonShowAll_Click(null, null);
        }

        private void buttonBrowseExportFolder_Click(object sender, EventArgs e)
        {
            DialogResult result = folderBrowserDialog1.ShowDialog();
            if (result == DialogResult.OK)
            {
                textBox2.Text = folderBrowserDialog1.SelectedPath;
            }
        }

        public Dictionary<string, bool> GetSelectedTags(TreeView tree)
        {
            TagsPerDocument.Clear();
            ListNodes(tree.Nodes[0]);
            return TagsPerDocument;
        }

        void ListNodes(TreeNode node)
        {
            if (node.Checked)
                TagsPerDocument.Add(node.Level +"->" + node.Name,true);

            foreach (TreeNode subnode in node.Nodes)
            {
                ListNodes(subnode);
            }
            // Print out node
        }

        private void buttonSearch_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();

            MongoCollection<Doc> _documents = md.GetCollection<Doc>(_dbName);

            
            //var linq = from tag in GetSelectedTags(treeView2) select (BsonValue)tag; 

            //var query1 = Query.In("Tags", values);

            //var query Query. = "{ tags: [ '";
            //foreach (string s in linq.ToArray())
            //{
            //    query+=s+"'";
            //}
            //query += "] }";

            //List<string> selectedTags = GetSelectedTags(treeView2).ToList<string>();
            //Doc[] dbEntries = (from entry in _documents.FindAll() select (Doc)entry).ToArray(); 

            //var p = from d in dbEntries
            //        where (selectedTags.Count > 0 && d.Tags.ToList<string>().Count>0 && (d.Tags.ToList<string>()).Except(selectedTags).ToList().Count == 0)
            //              || (selectedTags.Count == 0 && d.Tags.ToList<string>().Count==0)
                           
            //        select d;

            ////foreach (Doc item in _documents.Find(query))
            ////{
            ////    listBox1.Items.Add(item);
            ////}
            //foreach (Doc item in p.ToArray())
            //{
            //    listBox1.Items.Add(item);
            //}
            
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void clearAllEntriesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //md.Drop();
            //gfs.Files.Drop();
            //gfs.Chunks.Drop();


            MongoCollection<Doc> _documents = md.GetCollection<Doc>(_dbName);

            foreach (Doc item in _documents.FindAll())
            {
                //if ((string)listBox1.SelectedItem == item.DocName)
                {
                    ObjectId _documentid = new ObjectId(item.GridFsId.ToString());

                    MongoGridFSFileInfo _fileInfo = md.GridFS.FindOne(Query.EQ("_id", _documentid));

                    gfs.DeleteById(_documentid);
                }

            }
            _documents.RemoveAll();

            gfs.Database.RunCommand("repairDatabase");

            ListDb();
        }

        private void buttonShowAll_Click(object sender, EventArgs e)
        {
            listBox1.Items.Clear();

            MongoCollection<Doc> _documents = md.GetCollection<Doc>(_dbName);

            foreach (Doc item in _documents.FindAll())
            {
                listBox1.Items.Add(item);
            } 
        }
    }

    public class Doc
    {
        public ObjectId Id { get; set; }
        public string DocName { get; set; }
        public ObjectId GridFsId { get; set; }
        public Dictionary<string,bool> Tags { get; set;}
        public string Comment { get; set; }
        public string SubjectName { get; set; }
        public long FileSizeKb { get; set; }

        public Doc()
        {

        }

        public Doc(BsonDocument bson)
        {
            Id = (ObjectId) bson["_id"];
            DocName = (string)bson["DocName"];
            GridFsId =  (ObjectId) bson["GridFsId"];
            Comment = (string) bson["Comment"];
            SubjectName = (string) bson["SubjectName"];
            FileSizeKb = Convert.ToInt32(bson["FileSizeKb"]);
        }
        //BsonDocument bsondoc;

        //public Doc()
        //{
        //    //set extra fields
        //    bsondoc.Add("TagP300", true);
        //}

        //public BsonDocument getBsonExtraFields()
        //{
        //    return bsondoc;
        //}

        public override string ToString()
        {
            return DocName;
        }

        


    }
}
